package com.director.struts;

import com.director.core.DirectConfiguration;
import com.director.core.ExecutorAdapter;
import com.opensymphony.xwork2.config.Configuration;
import com.opensymphony.xwork2.config.ConfigurationException;
import com.opensymphony.xwork2.config.PackageProvider;
import com.opensymphony.xwork2.config.entities.ActionConfig;
import com.opensymphony.xwork2.config.entities.PackageConfig;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.util.logging.Logger;
import com.opensymphony.xwork2.util.logging.LoggerFactory;
import org.apache.commons.lang.xwork.StringUtils;
import org.apache.struts2.StrutsConstants;
import org.apache.struts2.dispatcher.Dispatcher;
import org.apache.struts2.dispatcher.DispatcherListener;

import java.util.Collection;
import java.util.StringTokenizer;

/**
 * @author Simone Ricciardi
 * @version 1.0, 04/25/2011
 */
public class DirectorConfigurationProvider implements PackageProvider, DispatcherListener {

   private static final Logger LOG = LoggerFactory.getLogger(DirectorConfigurationProvider.class);

   private static final String DEFAULT_ACTION_EXTENSION = ".action";

   private Configuration strutsConfig;
   private DirectConfiguration directConfig;
   private String providerParamName;
   private String preventScriptHijacking;
   private String wrapPrefix;
   private String wrapSuffix;
   private String actionExtension = DEFAULT_ACTION_EXTENSION;
   private String multiPartSaveDir;
   private String multiPartMaxSize;
   private ExecutorAdapter executorAdapter;

   @Inject(required = true)
   public void setDirectConfiguration(DirectConfiguration directConfig) {
      this.directConfig = directConfig;
   }

   @Inject(required = true)
   public void setExecutorAdapter(ExecutorAdapter executorAdapter) {
      this.executorAdapter = executorAdapter;
   }

   @Inject(value = "director.providerParamName", required = false)
   public void setProviderParamName(String providerParamName) {
      this.providerParamName = providerParamName;
   }

   @Inject(value = "director.preventScriptHijacking", required = false)
   public void setPreventScriptHijacking(String preventScriptHijacking) {
      this.preventScriptHijacking = preventScriptHijacking;
   }

   @Inject(value = "director.wrapPrefix", required = false)
   public void setWrapPrefix(String wrapPrefix) {
      this.wrapPrefix = wrapPrefix;
   }

   @Inject(value = "director.wrapSuffix", required = false)
   public void setWrapSuffix(String wrapSuffix) {
      this.wrapSuffix = wrapSuffix;
   }

   @Inject(value = StrutsConstants.STRUTS_ACTION_EXTENSION, required = false)
   public void setActionExtension(String actionExtension) {
      if(actionExtension.contains(",")) {
         StringTokenizer tk = new StringTokenizer(actionExtension, ",");
         actionExtension = tk.hasMoreTokens() ? tk.nextToken() : "";
      }
      this.actionExtension = "".equals(actionExtension) ? actionExtension : "."+ actionExtension;
   }

   @Inject(value = StrutsConstants.STRUTS_MULTIPART_SAVEDIR, required = false)
   public void setMultiPartSaveDir(String multiPartSaveDir) {
      this.multiPartSaveDir = multiPartSaveDir;
   }

   @Inject(value = StrutsConstants.STRUTS_MULTIPART_MAXSIZE, required = false)
   public void setMultiPartMaxSize(String multiPartMaxSize) {
      this.multiPartMaxSize = multiPartMaxSize;
   }

   public void init(Configuration configuration) throws ConfigurationException {
      LOG.info("Initializing Struts-Direct integration...");
      this.strutsConfig = configuration;
      Dispatcher.addDispatcherListener(this);
      this.overrideCustomDirectConfigs();
   }

   private void overrideCustomDirectConfigs() {
      if(this.providerParamName != null) {
         this.directConfig.setProviderParamName(this.providerParamName);
      }
      if(this.preventScriptHijacking != null) {
         this.directConfig.setPreventScriptHijacking("true".equals(preventScriptHijacking));
      }
      if(this.wrapPrefix != null) {
         this.directConfig.setWrapPrefix(wrapPrefix);
      }
      if(this.wrapSuffix != null) {
         this.directConfig.setWrapSuffix(wrapSuffix);
      }
      if(this.multiPartSaveDir != null) {
         this.directConfig.setUploadDir(this.multiPartSaveDir);
      }
      if(this.multiPartMaxSize != null) {
         this.directConfig.setUploadMaxSize(Long.parseLong(this.multiPartMaxSize));
      }
      this.directConfig.setRouterUrl(this.directConfig.getRouterUrl() + this.actionExtension);
      this.directConfig.registerAdapter(this.executorAdapter);
   }

   public boolean needsReload() {
      return false;
   }

   public void loadPackages() throws ConfigurationException {
   }

   public void dispatcherInitialized(Dispatcher du) {
      Collection<PackageConfig> packages = this.strutsConfig.getPackageConfigs().values();
      for(PackageConfig packageConfig : packages) {

         String nameSpace = packageConfig.getNamespace();
         Collection<ActionConfig> actions = packageConfig.getAllActionConfigs().values();

         for(ActionConfig actionConfig : actions) {

            String strutsActionName = actionConfig.getName();
            String className = actionConfig.getClassName();
            String methodName = actionConfig.getMethodName();

            if(StringUtils.isNotBlank(className) && StringUtils.isNotBlank(methodName)) {
               this.directConfig.registerMethod(className, methodName, nameSpace, null, strutsActionName);
            }
         }
      }
      LOG.info("... initialized Struts-Direct integration successfully");
   }

   public void dispatcherDestroyed(Dispatcher du) {
   }
}
